var $ = function (el) {
    return document.querySelector(el)
};
var $$ = function (el) {
    return document.querySelectorAll(el)
};
var timer = {};
var clipboardTimer = null;
var secretMap = {};
var tokenMap = {};
var config_rev = null;
var fileJsonOpenInput = document.getElementById('file-json-open-input');
var fileQrOpenInput = document.getElementById('file-qr-open-input');
var config = [];
var delay_id = null;

//初始化
if (typeof utools == 'object') {
    utools.onPluginReady(() => {
        returnMain();
    });
} else {
    returnMain();
}

//导入文件
$('#menu-open-file').onclick = function (e) {
    if (fileJsonOpenInput) {
        fileJsonOpenInput.value = ''; // force 'onchange' event
        fileJsonOpenInput.click();
    }
}

//导入二维码
$('#menu-open-qr').onclick = function (e) {
    if (fileQrOpenInput) {
        fileQrOpenInput.value = ''; // force 'onchange' event
        fileQrOpenInput.click();
    }
}

//打开帮助页面
$('#menu-help').onclick = function (e) {
    openPage('help');
}

//打开编辑页面
$('#menu-edit').onclick = function (e) {
    returnEdit();
}

//打开增加页面
$('#menu-add').onclick = function (e) {
    addMessage();
    returnMain();
}

//导出文件
$('#menu-import').onclick = function (e) {
    var items = config;
    for (var i = 0; i < items.length; i++) {
        items[i].secret = encryption(items[i].secret)
        delete items[i].identifier;
        delete items[i].algorithm;
    }
    downFile(JSON.stringify(items), "config.json");
}

//跳转到主界面
function returnMain() {
    loadConfig();
    loadItems(true);
    openPage('main');
}

//导入json文件
fileJsonOpenInput.onchange = function (e) {
    var file = fileJsonOpenInput.files[0];
    var reader = new FileReader();
    reader.onload = function (readerEvt) {
        var items = JSON.parse(parseEncryptedJson(reader.result));
        if (items.length > 0) {
            config = [];
            for (var i = 0; i < items.length; i++) {
                if (checkProvider(items[i])) {
                    addProvider(items[i]);
                    returnMain();
                }
            }
        }
    }
    reader.readAsText(file);
}

//导入二维码文件
fileQrOpenInput.onchange = function (e) {
    var file = e.target.files[0];
    if (window.FileReader) {
        var fr = new FileReader();
        fr.readAsDataURL(file);
        fr.onloadend = function (e) {
            var c = document.getElementById("qrcanvas");
            var ctx = c.getContext("2d");
            var img = new Image();
            img.src = e.target.result;
            img.onload = function () {
                $("#qrcanvas").style.height = img.height;
                $("#qrcanvas").style.width = img.width;
                ctx.drawImage(img, 0, 0, img.width, img.height);
                var imageData = ctx.getImageData(0, 0, img.width, img.height);
                const code = jsQR(imageData.data, imageData.width, imageData.height, {
                    inversionAttempts: "dontInvert",
                });
                if (code) {
                    var data = code.data;
                    if (data !== '') {
                        if (data.startsWith("otpauth://totp")) {
                            var indexOf = data.indexOf("secret=");
                            var txtLength = data.indexOf("&issuer") - indexOf;
                            var secret = data.substr(indexOf + 7, txtLength - 7);
                            if (secret !== '') {
                                saveMessage(secret);
                                return;
                            }
                        }
                    }
                    showMessageBox('秘钥格式不正确', "error", 3000);
                } else {
                    showMessageBox("识别错误", "error", 3000)
                }
            };
        }
    }
}

//跳转到删除界面
function returnEdit() {
    loadConfig();
    loadItems(false);
    openPage('edit');
}

//二维码添加界面
function saveMessage(secret) {
    showInputBox(["名称", "描述", "更新时间", "口令长度", "秘钥前缀，为空可不填"], "输入添加信息")
        .then(inputs => {
            var provider = {};
            var name = inputs[0];
            if (name === '') {
                var file = $("#file-qr-open-input").value;
                file = file.substring(file.lastIndexOf("\\") + 1, file.lastIndexOf("."));
                name = file;
            }
            provider.provider = name;
            provider.description = inputs[1];
            provider.secret = secret;
            provider.period = inputs[2];
            provider.digits = inputs[3];
            provider.preSecret = inputs[4];
            provider.indicatorColor = inputs[5];
            if (addProvider(provider)) {
                showMessageBox('添加成功', "success", 1500);
            }
            returnMain();
        })
}

//手动添加界面
function addMessage() {
    showInputBox(["名称", "描述", "更新时间", "口令长度", "秘钥", "秘钥前缀，为空可不填"], "输入添加信息")
        .then(inputs => {
            var provider = {};
            provider.provider = inputs[0];
            provider.description = inputs[1];
            provider.period = inputs[2];
            provider.digits = inputs[3];
            provider.secret = inputs[4];
            provider.preSecret = inputs[5];
            if (addProvider(provider)) {
                showMessageBox("添加成功", "success", 1500);
            }
            returnMain();
        })
}

//手动修改界面
function updateMessage(providerName) {
    var provider = {};
    for (var i = 0; i < config.length; i++) {
        if (config[i].provider === providerName) {
            provider = config[i];
        }
    }
    if (provider == null) {
        showMessageBox("暂不存在该信息", "error", 1500);
        return;
    }
    showInputBox(["描述：" + provider.description, "更新时间：" + provider.period, "口令长度：" + provider.digits, "秘钥：" + encryption(provider.secret), "秘钥前缀，为空可不填 " + (provider.preSecret || '')], "输入" + provider.provider + "的修改信息")
        .then(inputs => {
            provider.description = checkValue(inputs[0], provider.description);
            provider.period = checkValue(inputs[1], provider.period);
            provider.digits = checkValue(inputs[2], provider.digits);
            provider.secret = checkValue(inputs[3], provider.secret);
            provider.preSecret = checkValue(inputs[4], provider.preSecret);
            if (updateProvider(provider)) {
                showMessageBox("修改成功", "success", 1500);
            }
            returnEdit();
        })
}

function checkValue(input, defaultValue) {
    if (input === undefined || input === '') {
        return defaultValue;
    }
    return input;
}


function saveOptionToDb() {
    if (typeof utools == 'object') {
        // 保存配置
        utools.db.put({
            _id: "config",
            data: JSON.stringify(config),
            _rev: config_rev
        })
    }
}

// 从数据库加载配置
function loadConfig() {
    if (typeof utools == 'object') {
        let result = utools.db.get("config");
        if (result) {
            config_rev = result._rev;
            config = JSON.parse(parseEncryptedJson(result.data));
        }
    } else {
        if (config.length === 0) {
            var jsonStr = document.getElementById("txt_demo").textContent;
            config = JSON.parse(parseEncryptedJson(jsonStr));
        }
    }
}

function downFile(content, filename) {
    var ele = document.createElement('a');// 创建下载链接
    ele.download = filename;//设置下载的名称
    ele.style.display = 'none';// 隐藏的可下载链接
    // 字符内容转变成blob地址
    var blob = new Blob([content]);
    ele.href = URL.createObjectURL(blob);
    // 绑定点击时间
    document.body.appendChild(ele);
    ele.click();
    // 然后移除
    document.body.removeChild(ele);
};

function encryption(str) {
    let len = parseInt(str.length / 5);
    return str.substr(0, len) + ''.padStart(str.length - (len * 2), '*') + str.substr(len * -1);
};

//添加
function addProvider(provider) {
    if (checkProvider(provider)) {
        var tmp = {};
        tmp.provider = provider.provider;
        tmp.secret = provider.secret;
        tmp.description = checkValue(provider.description, '');
        tmp.digits = checkValue(provider.digits, 6);
        tmp.period = checkValue(provider.period, 30);
        tmp.indicatorColor = colorRGB2Hex(checkValue(provider.indicatorColor, '#ff0000'));
        tmp.algorithm = checkValue(provider.algorithm, 'SHA1');
        tmp.preSecret = checkValue(provider.preSecret, '');
        config.push(tmp);
        saveOptionToDb();
        return true;
    }
    return false;
};

//修改
function updateProvider(provider) {
    if (checkProviderByName(provider)) {
        for (var i = 0; i < config.length; i++) {
            if (config[i].provider == provider.provider) {
                config[i] = provider;
                saveOptionToDb();
                return true;
            }
        }
    }
    return false;
};


function updateProgressBar(item, reChange) {
    var nowInSecs = Math.floor(new Date().getTime() / 1000);
    var period = parseInt(item.getAttribute('data-period'));
    var provider = item.getAttribute('data-provider');
    var identifier = item.getAttribute('data-identifier');
    var preSecret = item.getAttribute('data-preSecret');
    // Modulo per "period" seconds
    var newTokenInSecs = (period - (nowInSecs % period) - 1);
    var percentage = newTokenInSecs * 100 / period;
    if (reChange || newTokenInSecs === period - 1) {
        tokenMap[identifier] = new OTPAuth.TOTP({
            algorithm: item.getAttribute('data-algorithm'),
            digits: item.getAttribute('data-digits'),
            period: period,
            secret: OTPAuth.Secret.fromBase32(secretMap[identifier])
        });
        item.querySelector('.item-token').innerText = preSecret + tokenMap[identifier].generate();
    }
    item.querySelector('.item-expires-progress').style.width = percentage + '%';
    item.querySelector('.item-second').innerText = newTokenInSecs;
    timer[provider] = setTimeout(function () {
        updateProgressBar(item, false);
    }, 1000);
}

function resetState(view) {
    if (view) {
        for (timerName in timer) {
            clearTimeout(timer[timerName]);
        }
        secretMap = {};
        tokenMap = {};
        timer = {};
    }
    var itemsNode;
    if (view) {
        itemsNode = $('.items-container');
    } else {
        itemsNode = $('.edit-container');
    }
    while (itemsNode.firstChild) {
        itemsNode.removeChild(itemsNode.lastChild);
    }
}

function openPage(name) {
    var pages = $$('.pages');
    for (var i = 0; i < pages.length; i++) {
        if (pages[i].className.indexOf(name) === -1) {
            pages[i].style.display = 'none';
            continue;
        }
        pages[i].style.display = 'block';
    }
}

function copyToClipboard(text) {
    clipboardTimer && clearTimeout(clipboardTimer);
    // Temporarily create textarea to be able to select text
    var elem = document.createElement('textarea');
    elem.value = text;
    document.body.appendChild(elem);
    elem.select();
    document.execCommand('copy');
    document.body.removeChild(elem);
    $('.item-copied').style.display = 'inline-block';
    $('.item-copied').innerHTML = '<p>&quot;' + text + '&quot; 复制到剪切板</p>'
    clipboardTimer = setTimeout(function hideText() {
        $('.item-copied').style.display = 'none';
    }, 3000);
}


//根据名称删除
function deleteByProvider(provider) {
    showConfirmBox("确定删除 " + provider + " 全部信息").then(flag => {
        if (flag === true) {
            deleteProvider(provider);
            returnEdit();
        }
    });
}

//根据名称删除
function deleteProvider(provider) {
    if (provider != '') {
        if (config.length > 0) {
            var items = [];
            for (var i = 0; i < config.length; i++) {
                if (config[i].provider != provider) {
                    items.push(config[i]);
                }
            }
            config = items;
            saveOptionToDb();
        }
    }
};

//名称校验
function checkProvider(provider) {
    if (checkProviderByName(provider)) {
        if (config.length > 0) {
            for (var i = 0; i < config.length; i++) {
                if (config[i].provider == provider.provider) {
                    provider.provider += '-名称重复';
                }
            }
        }
        return true;
    }
    showMessageBox("请验证输入内容是否正确", "error", 1500);
    return false
}

//校验数据
function checkProviderByName(provider) {
    if (provider != null) {
        if (provider.provider !== '' && provider.secret !== '') {
            return true;
        }
    }
    return false
}


//输入框通用方法
function showInputBox(placeHolders = [""], title = '') {
    return new Promise((reslove, reject) => {
        if (!(placeHolders instanceof Array)) placeHolders = [placeHolders.toString()]
        if (typeof utools == 'object') utools.setExpendHeight(550)
        var html = ""
        var inputBoxNumbers = placeHolders.length
        for (let i = 0; i < inputBoxNumbers; i++) {
            html += `<input class="swal2-input" id="inputBox${i}" placeholder="${placeHolders[i]}">`
        }
        var result = []
        var options = {
            onBeforeOpen: () => {
                document.getElementById(`inputBox0`).focus()
                $('.swal2-content').click(function (e) {
                    e.which == 13 && swal.clickConfirm()
                })
                if (typeof utools == 'object') utools.setExpendHeight(550);
            },
            title: title,
            html: html,
            focusConfirm: false,
            showCancelButton: true,
            confirmButtonText: '保存',
            cancelButtonText: '取消',
            background: '#272626',
            preConfirm: () => {
                for (let i = 0; i < inputBoxNumbers; i++) {
                    result.push(document.getElementById(`inputBox${i}`).value)
                }
                reslove(result)
            }
        }
        swalOneByOne(options)
    });
}

// 显示自动消失的提示框
function showMessageBox(title, icon = "success", time = 1500) {
    var options = {
        icon: icon,
        title: title,
        toast: true,
        position: 'top',
        timer: time,
        showConfirmButton: false,
        background: '#272020',
    }
    swal.fire(options)
}


async function showConfirmBox(title) {
    let options = {
        text: title,
        icon: 'warning',
        showCancelButton: true,
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        background: '#272020',
    }
    if (typeof utools == 'object') utools.setExpendHeight(550);
    let result = await Swal.fire(options);
    if (result.value) return true;
}

function createItem(options, view) {
    var itemHtml = '<div class="item" data-identifier="' + options.identifier + '" data-algorithm="' + (options.algorithm || 'SHA1') + '" ' +
        'data-provider="' + options.provider + '" data-digits="' + (options.digits || 6) + '" data-period="' + (options.period || 30) + '"' +
        'data-preSecret="' + (options.preSecret || '') + '"' + ' data-indicatorColor="' + (options.indicatorColor || '#ff0000') + '">';
    if (view) {
        itemHtml += '<h3 class="item-title">' + (options.provider || 'error') + '</h3>';
    } else {
        itemHtml += '<h3 class="item-title" onclick="updateMessage(\'' + options.provider + '\')" title="点击编辑">' + (options.provider || 'error') + '</h3>';
    }
    itemHtml += '<p class="item-desc">' + (options.description || '') + '</p>';
    itemHtml += '<p class="item-second">' + (options.period || 30) + '</p>';
    var node;
    if (view) {
        node = $('.items-container');
        itemHtml += '<h4 class="item-token" onclick="copyToClipboard(this.innerText)" title="点击复制">000000</h4>';
        itemHtml += '<div style="background-color: ' + colorRGB2Hex(options.indicatorColor) + '" class="item-expires"><div class="item-expires-progress" style="width: 0%"></div></div>';
    } else {
        node = $('.edit-container');
        itemHtml += '<h4 class="item-token" onclick="deleteByProvider(\'' + options.provider + '\')" title="点击删除">' + (options.preSecret || '') + ' ' + encryption(options.secret) + '</h4>';
        itemHtml += '<div style="background-color: ' + colorRGB2Hex(options.indicatorColor) + '" class="item-expires" id="' + options.provider + '" title="点击修改颜色"><div class="item-expires-progress" style="width: 0%"></div></div>';
    }
    node.insertAdjacentHTML('beforeend', itemHtml);
}

function parseEncryptedJson(jsonData) {
    jsonData = jsonData.trim();
    if (jsonData.charAt(0) === '[') {
        return jsonData;
    }
    const password = prompt('Enter passphrase');
    if (password === null) {
        throw 'Can not decrypt file, invalid passphrase.';
    }
    return CryptoJS.AES.decrypt(jsonData, password).toString(CryptoJS.enc.Utf8);
}

function loadItems(view) {
    let i;
    resetState(view);
    try {
        var items = config;
        for (i = 0; i < items.length; i++) {
            try {
                if (view) {
                    var identifier = items[i].provider + '-' + i;
                    items[i].identifier = identifier;
                    secretMap[identifier] = items[i].secret;
                    createItem(items[i], view);
                } else {
                    createItem(items[i], view);
                }
            } catch (e) {
                showMessageBox('数据异常，文件已删除，请重启插件', "error", 3000);
                deleteProvider(items[i].provider)
                loadItems(view);
                break;
            }
        }
        if (view) {
            var items = $$('.items-container .item');
            for (i = 0; i < items.length; i++) {
                try {
                    updateProgressBar(items[i], true);
                } catch (e) {
                    deleteProvider(items[i].getAttribute('data-provider'));
                    showMessageBox("数据异常，已进行删除", "error", 1500);
                    loadItems(view);
                }
            }
            $('.items-container').insertAdjacentHTML('beforeend', '  <div class="item-copied"><p>复制到剪切板</p></div>');
        } else {
            var items = $$('.edit-container .item');
            for (i = 0; i < items.length; i++) {
                try {
                    Colorpicker.create({
                        el: items[i].getAttribute('data-provider'),
                        color: items[i].getAttribute('data-indicatorColor'),
                        change: function (elem, hex) {
                            if (colorRGB2Hex(elem.style.backgroundColor) != hex) {
                                elem.style.backgroundColor = hex;
                                updateIndicatorColor(elem.getAttribute('id'), hex);
                            }
                        }
                    });
                } catch (e) {
                    deleteProvider(items[i].getAttribute('data-provider'));
                    showMessageBox("数据异常，已进行删除", "error", 1500);
                    loadItems(view);
                }
            }
        }
    } catch (e) {
        showMessageBox('数据异常，请重新导入配置文件', "error", 3000);
        //deleteAllProvider();
        loadItems(view);
    }
}


//更新进度条颜色
function updateIndicatorColor(provider, hex) {
    if (provider !== '' && hex !== '') {
        for (var i = 0; i < config.length; i++) {
            if (config[i].provider === provider) {
                config[i].indicatorColor = hex;
                filter_delay();
            }
        }
    }
}


/**
 * 过滤输入抖动
 * @param timeout
 */
function filter_delay(timeout) {
    timeout = typeof timeout == "number" ? timeout : 500;
    // 设置定时器 用于输入抖动
    delay_id && clearTimeout(delay_id);
    delay_id = setTimeout(() => {
        try {
            saveOptionToDb();
        } catch (error) {
            console.log("保存出错")
        }
    }, timeout);
}


//rgb转16进制
function colorRGB2Hex(color) {
    if (color !== '') {
        if (color.startsWith("#")) {
            return color;
        }
        if (color.startsWith("rgb")) {
            var rgb = color.split(',');
            var r = parseInt(rgb[0].split('(')[1]);
            var g = parseInt(rgb[1]);
            var b = parseInt(rgb[2].split(')')[0]);
            return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
        }
    }
    return "#ff0000"
}


function swalOneByOne(options) {
    swal.getQueueStep() ? Swal.insertQueueStep(options) : Swal.queue([options])
}

